package soulkun.library.utils.file

import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.StatFs
import android.provider.MediaStore
import androidx.core.content.FileProvider
import soulkun.library.LibraryInit
import soulkun.library.helper.fileprovider.FileProviderHelper
import soulkun.library.utils.io.StreamUtils
import soulkun.library.utils.string.StringUtils
import java.io.*
import java.nio.charset.Charset

object FileUtils {

    fun getSize(file: File?): Long {
        var size: Long = 0
        if (file == null) {
            return size
        }
        if (file.exists()) {
            if (file.isDirectory) {
                val children = file.listFiles()
                if (children != null) {
                    for (child in children) {
                        size += getSize(child)
                    }
                }
            } else {
                size = file.length()
            }
        }
        return size
    }

    fun delete(file: File?): Boolean {
        if (file == null) {
            return false
        }
        var success = true
        if (file.exists()) {
            if (file.isDirectory) {
                val children = file.listFiles()
                if (children != null) {
                    for (child in children) {
                        success = success and delete(child)
                    }
                }
            } else {
                return file.delete()
            }
        }
        return success
    }

    fun copy(source: File?, target: File?) {
        try {
            val `is`: InputStream = FileInputStream(source)
            val os: OutputStream = FileOutputStream(target)
            StreamUtils.copy(`is`, os)
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        }
    }

    fun formatBytes(size: Long): String? {
        val kb = size / 1024
        return if (kb >= 1024L * 1024 * 1024 * 1024) {
            StringUtils.format("%.2fPB", kb / 1024f / 1024f / 1024f / 1024f)
        } else if (kb >= 1024L * 1024 * 1024) {
            StringUtils.format("%.2fTB", kb / 1024f / 1024f / 1024f)
        } else if (kb >= 1024 * 1024) {
            StringUtils.format("%.2fGB", kb / 1024f / 1024f)
        } else if (kb >= 1024 * 100) {
            StringUtils.format("%dMB", (kb / 1024f + 0.5f).toInt())
        } else if (kb >= 1024) {
            StringUtils.format("%.2fMB", kb / 1024f)
        } else if (kb >= 0) {
            StringUtils.format("%dKB", kb)
        } else {
            "0KB"
        }
    }

    fun getUri(file: File?): Uri? {
        if (file == null) {
            return null
        }
        return if (Build.VERSION.SDK_INT >= 24) {
            FileProvider.getUriForFile(
                LibraryInit.context,
                FileProviderHelper.AUTHORITIES ?: "",
                file
            )
        } else {
            Uri.fromFile(file)
        }
    }

    fun getEmptyUri(file: File): Uri? {
        try {
            if (file.exists()) {
                file.delete()
            }
            file.createNewFile()
        } catch (ignore: IOException) {
        }
        return getUri(file)
    }

    fun getAvailableBytes(): Long {
        val path = Environment.getDataDirectory()
        val stat = StatFs(path.path)
        return stat.availableBytes
    }

    fun getTotalBytes(): Long {
        val path = Environment.getExternalStorageDirectory()
        val stat = StatFs(path.path)
        return stat.totalBytes
    }

    fun getApplicationExternalCacheDirectory(context: Context, dirName: String): File{
        val applicationContext = context.applicationContext
        return applicationContext.externalCacheDirs[0]!!.let {
            File(it, dirName).apply {
                mkdirs()
            }
        }
    }

    fun getApplicationExternalFileDirectory(context: Context, dirName: String): File{
        val applicationContext = context.applicationContext
        return applicationContext.getExternalFilesDir(null)!!.let {
            File(it, dirName).apply {
                mkdirs()
            }
        }
    }

    fun getApplicationInternalCacheDirectory(context: Context, dirName: String): File{
        val applicationContext = context.applicationContext
        return applicationContext.cacheDir!!.let {
            File(it, dirName).apply {
                mkdirs()
            }
        }
    }

    fun getApplicationInternalFileDirectory(context: Context, dirName: String): File{
        val applicationContext = context.applicationContext
        return applicationContext.filesDir!!.let {
            File(it, dirName).apply {
                mkdirs()
            }
        }
    }

    fun bitmapToFile(
        context: Context,
        bitmap: Bitmap,
        file: File,
        isNeedAddToMediaStore: Boolean,
        dirName: String
    ): Boolean {
        return try {
            if (!file.exists()) file.createNewFile()
            val bufferedOutputStream = BufferedOutputStream(FileOutputStream(file))
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bufferedOutputStream)
            bufferedOutputStream.flush()
            bufferedOutputStream.close()
            if (isNeedAddToMediaStore) {
                bitmapToMediaStore(context, bitmap, file.name, dirName)
            }
            true
        } catch (e: IOException) {
            e.printStackTrace()
            false
        }
    }

    //调用系统方法自动保存至相册，不能设置路径，需要申请写入权限
    fun bitmapToMediaStoreAuto(context: Context, bitmap: Bitmap, fileName: String): String {
        val result = MediaStore.Images.Media.insertImage(
            context.contentResolver,
            bitmap,
            fileName,
            "彩虹屁"
        )
        context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(result)))
        return result
    }

    //保存成到系统相册中，可设置路径，需要申请写入权限
    fun bitmapToMediaStore(context: Context, bitmap: Bitmap, fileName: String, dirName: String): String{
        val contentResolver = context.contentResolver
        val contentValues = ContentValues().apply {
            put(MediaStore.Images.ImageColumns.RELATIVE_PATH, "Pictures/$dirName/");
            put(MediaStore.Images.ImageColumns.DISPLAY_NAME, fileName)
            put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpeg")
            put(MediaStore.Images.ImageColumns.WIDTH, bitmap.width)
            put(MediaStore.Images.ImageColumns.HEIGHT, bitmap.height)
        }
        val uri = contentResolver.insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            contentValues
        )
                ?: return ""
        var outputStream: OutputStream?= null
        try {
            outputStream = contentResolver.openOutputStream(uri)
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
        } catch (e: Exception) {
            e.printStackTrace()
        }finally {
            try {
                if (outputStream != null) {
                    outputStream.flush()
                    outputStream.close()
                }
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        return "${Environment.getExternalStorageDirectory()}/Pictures/$dirName/$fileName.jpg"
    }

    /**
     * 读取asset目录下文件。
     *
     * @return content
     */
    fun readAssertFile(context: Context, file: String, code: Charset): String {
        var len = 0
        var buf: ByteArray? = null
        var result = ""
        try {
            val `in` = context.assets.open(file!!)
            len = `in`.available()
            buf = ByteArray(len)
            `in`.read(buf, 0, len)
            result = String(buf, code)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return result
    }

}